<template>
  <div id="app">
    <div class="chat">
      <div class="head">
        ChatGPT - 聊天
        <a-button type="primary" @click="remain">查看余额</a-button>
      </div>

      <div id="chat-body" class="body">
        <!-- 对话内容 -->
        <div :key="item" v-for="(v,item) in msg" class="chat-msg" :class="v.role">
          <a-avatar v-if="v.role=='assistant'" :size="30" :src="src"></a-avatar>
          <div v-if="v.role!='system'" class="content" v-html="v.role=='user'?v.content:marked.parse(v.content)"></div>
        </div>
        <!-- AI输入中 -->
        <div v-show="!canSend" class="chat-msg assistant">
          <a-avatar :size="30" :src="src"></a-avatar>
          <div class="content" v-html="marked.parse(tmpTxt+'\n')"></div>
        </div>
      </div>

      <div class="footer">
        <input v-model="input" autosize type="textarea" placeholder="请输入内容" @keypress="pressEnter">
        <a-button type="primary" :disabled="!canSend" style="margin-left:20px;" @click="send">发送</a-button>
      </div>
    </div>
  </div>
</template>

<script>
// import hljs from 'highlight.js';
import axios from 'axios';
// import {info} from "@/api/module/chatGptUser";
// import {marked} from 'marked';
// import {message} from 'ant-design-vue';
// import {send} from "@/api/module/chatGpt";

export default {
  data() {
    return {
      baseUrl: '',//api地址
      apikey: '',//key
      msg: [{role: 'system', content: '以markdown格式回答'}],//所有对话
      input: '',//输入
      canSend: true,
      tmpTxt: '',//临时文本
      src: '',//GPT的logo
      open:false,
    }
  },
  created() {
    this.marked = marked,
      this.getImg(),
      this.getUserInfo()
  },
  methods: {
    //获取密钥和url
    getUserInfo() {
      info().then((response) => {
          if(response.success){
            this.apikey=response.data.key;
            this.baseUrl=response.data.url;
            this.open=true;
          }else {
            message.error({content: response.msg, key:'send', duration: 1})
          }
      })
    },

    //查看余额
    remain() {
      message.error({content: '官方已关闭该接口！', key: 'send', duration: 1});
      return
    },
    //回车
    pressEnter() {
      if (event.keyCode == 13) {
        event.preventDefault()//禁止默认换行
        this.send()
      }
    },
    //发送消息
    send() {
      //判断token
      if (!this.open){
        message.error({content: '未打开接口！', key: 'send', duration: 1});
        return
      }
      //判断发言
      if (!this.input) {
        message.error({content: '请输入问题!', key: 'send', duration: 1});
        return
      }

      //显示你的发言
      this.msg.push({role: 'user', content: this.input})

      //清空输入框
      this.input = ''

      //禁止输入和发送
      this.canSend = false

      //获取元素用于滚动
      let chatBody = document.getElementById('chat-body')

      fetch(this.baseUrl + '/v1/chat/completions', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer ' + this.apikey
        },
        body: JSON.stringify({
          model: 'gpt-3.5-turbo',
          messages: this.msg,
          temperature: 0.6,//创意度
          stream: true,
        }),
      }).then(o => {
        let reader = o.body.getReader()
        let readStream = (reader) => {
          reader.read().then(({done, value}) => {
            //结束处理
            if (done) {
              this.msg.push({role: 'assistant', content: this.tmpTxt})
              this.canSend = true
              this.tmpTxt = ''

              //消息长度控制在30
              let spli = this.msg.length - 30
              if (spli > 0) this.msg.splice(0, spli)

              //滚动到底部
              chatBody.scrollTop = chatBody.scrollHeight

              //代码高亮
              this.$nextTick(() => {
                hljs.highlightAll()
              })

              return
            }

            let decodeds = new TextDecoder().decode(value)
            let decodedArray = decodeds.split('data: ')

            decodedArray.forEach(v => {
              if (!v || v.trim() == '[DONE]') return
              let json = JSON.parse(v)
              let text = json.choices[0].delta.content ?? ''
              if (text) this.tmpTxt += text
            })

            //滚动到底部
            chatBody.scrollTop = chatBody.scrollHeight

            readStream(reader)
          })
        }

        readStream(reader)
      }).catch(e => {
        message.error({content: e.message, key: 'send', duration: 1});
      })
    },

    getImg() {
      this.src = require('@/assets/logo.png')
    }
  }
}
</script>

<style scoped>
html, body, #app {
  height: 100%;
  margin: 0;
}

p {
  margin: 0;
}

.chat {
  background-color: #272a37;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.chat .head {
  text-align: center;
  padding: 20px;
  color: #fff;
}

.chat .body {
  background-color: #323644;
  overflow: auto;
  height: 100%;
}

.chat .body::-webkit-scrollbar {
  width: 5px;
}

.chat .body::-webkit-scrollbar-track {
  background: #e0e0e0;
  border-radius: 3px;
}

.chat .body::-webkit-scrollbar-thumb {
  background-color: #c2c2c2;
  border-radius: 3px;
}

.chat-msg {
  display: flex;
  padding: 20px 10px 10px 10px;
}

.chat .body .assistant {
  justify-content: flex-start;
}

.chat .body .assistant .content {
  background-color: #d9d9d9;
}

.chat .body .user {
  justify-content: flex-end;
}

.chat .body .user .content {
  background-color: #1d90f5;
  color: #fff;
}

.chat-msg .content {
  max-width: 70%;
  margin: 0 10px;
  padding: 10px;
  border-radius: 8px;
}

.chat .footer {
  padding: 20px;
  display: flex;
  justify-content: space-between;

}

.chat .footer input[type="textarea"] {
  width: 90%;
  flex: 1;
  margin-right: 10px;
  border-radius: 5px;
  border: none;
  outline: none;
  color: white;
  background-color: rgb(68, 70, 84);
}
</style>
